x86: allow Dom0 to drive PC speaker
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Wed, 12 Sep 2007 14:32:58 +0000 (15:32 +0100)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Wed, 12 Sep 2007 14:32:58 +0000 (15:32 +0100)
as long as Xen doesn't itself make use of PIT channel 2.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/hvm/i8254.c
xen/arch/x86/time.c
xen/include/asm-x86/time.h

index 2aa3c1a5ba53ce0518adb7507e9b14e6cb7d4772..d10b6ef2eea34fdfe77a3744ab37fbff365b74e8 100644 (file)
@@ -598,11 +598,13 @@ int pv_pit_handler(int port, int data, int write)
         .size = 1,
         .type = IOREQ_TYPE_PIO,
         .addr = port,
-        .dir  = write ? 0 : 1,
-        .data = write ? data : 0,
+        .dir  = write ? IOREQ_WRITE : IOREQ_READ,
+        .data = data
     };
 
-    if ( port == 0x61 )
+    if ( (current->domain->domain_id == 0) && dom0_pit_access(&ioreq) )
+        /* nothing to do */;
+    else if ( port == 0x61 )
         handle_speaker_io(&ioreq);
     else
         handle_pit_io(&ioreq);
index 5fefd20080ef5806b2f839a200b6b92dc2dcca82..5465cc056e1977d3400a670716ad7d7a60dbe94c 100644 (file)
@@ -177,7 +177,6 @@ static u64 init_pit_and_calibrate_tsc(void)
     unsigned long count;
 
     /* Set PIT channel 0 to HZ Hz. */
-#define CLOCK_TICK_RATE 1193180 /* crystal freq (Hz) */
 #define LATCH (((CLOCK_TICK_RATE)+(HZ/2))/HZ)
     outb_p(0x34, PIT_MODE);        /* binary, mode 2, LSB/MSB, ch 0 */
     outb_p(LATCH & 0xff, PIT_CH0); /* LSB */
@@ -972,6 +971,50 @@ int time_resume(void)
     return 0;
 }
 
+int dom0_pit_access(struct ioreq *ioreq)
+{
+    /* Is Xen using Channel 2? Then disallow direct dom0 access. */
+    if ( plt_src.read_counter == read_pit_count )
+        return 0;
+
+    switch ( ioreq->addr )
+    {
+    case PIT_CH2:
+        if ( ioreq->dir == IOREQ_READ )
+            ioreq->data = inb(PIT_CH2);
+        else
+            outb(ioreq->data, PIT_CH2);
+        return 1;
+
+    case PIT_MODE:
+        if ( ioreq->dir == IOREQ_READ )
+            return 0; /* urk! */
+        switch ( ioreq->data & 0xc0 )
+        {
+        case 0xc0: /* Read Back */
+            if ( ioreq->data & 0x08 )    /* Select Channel 2? */
+                outb(ioreq->data & 0xf8, PIT_MODE);
+            if ( !(ioreq->data & 0x06) ) /* Select Channel 0/1? */
+                return 1; /* no - we're done */
+            /* Filter Channel 2 and reserved bit 0. */
+            ioreq->data &= ~0x09;
+            return 0; /* emulate ch0/1 readback */
+        case 0x80: /* Select Counter 2 */
+            outb(ioreq->data, PIT_MODE);
+            return 1;
+        }
+
+    case 0x61:
+        if ( ioreq->dir == IOREQ_READ )
+            ioreq->data = inb(0x61);
+        else
+            outb((inb(0x61) & ~3) | (ioreq->data & 3), 0x61);
+        return 1;
+    }
+
+    return 0;
+}
+
 /*
  * Local variables:
  * mode: C
index 85bc78bfbd73eb917343bcd4c17ad976f7fe355b..773c3127700b77de82de528f6c3598ec3eac21c5 100644 (file)
@@ -4,8 +4,8 @@
 
 #include <asm/msr.h>
 
-extern void calibrate_tsc_bp(void);
-extern void calibrate_tsc_ap(void);
+void calibrate_tsc_bp(void);
+void calibrate_tsc_ap(void);
 
 typedef u64 cycles_t;
 
@@ -21,9 +21,12 @@ mktime (unsigned int year, unsigned int mon,
         unsigned int day, unsigned int hour,
         unsigned int min, unsigned int sec);
 
-extern int time_suspend(void);
-extern int time_resume(void);
+int time_suspend(void);
+int time_resume(void);
 
-extern void init_percpu_time(void);
+void init_percpu_time(void);
+
+struct ioreq;
+int dom0_pit_access(struct ioreq *ioreq);
 
 #endif /* __X86_TIME_H__ */